package cn.sciento.transfer.app.service.impl;

import com.google.common.collect.ImmutableList;
import java.util.List;
import cn.sciento.transfer.app.service.DistributionIdService;
import cn.sciento.transfer.domain.entity.DistributionId;
import cn.sciento.transfer.domain.repository.DistributionIdRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

@Service
public class DistributionIdServiceImpl implements DistributionIdService {
  public static final Logger LOGGER = LoggerFactory.getLogger(DistributionIdServiceImpl.class);
  
  public static final String DISTRIBUTION_ID_KEY = "hdtt:distribution-id";
  
  public static final Long DISTRIBUTION_ID_INCR_STEP = Long.valueOf(1L);
  
  public static final String DISTRIBUTION_ID_LUA_METHOD_GET = "getDistributionId";
  
  public static final Integer DISTRIBUTION_ID_RESULT_SUCC_COUNT = Integer.valueOf(3);
  
  @Autowired
  private StringRedisTemplate stringRedisTemplate;
  
  @Autowired
  private RedisScript<String> distributionIdGeneratorLua;
  
  @Autowired
  private DistributionIdRepository distributionIdRepository;
  
  public Long getDistributionId(String bizType) {
    String key = "hdtt:distribution-id:" + bizType;
    Long currentMilliSeconds = this.stringRedisTemplate.execute((RedisConnection connection) -> {
      return connection.time();
    });
    String currentValueStr = (String)this.stringRedisTemplate.execute(this.distributionIdGeneratorLua, ImmutableList.of(key), new Object[]{"getDistributionId", String.valueOf(DISTRIBUTION_ID_INCR_STEP), String.valueOf(currentMilliSeconds)});
    if (StringUtils.isEmpty(currentValueStr)) {
      DistributionId sample = new DistributionId();
      sample.setBizType(bizType);
      DistributionId distributionId = (DistributionId)this.distributionIdRepository.selectOne(sample);
      Assert.notNull(distributionId, "Distribution cannot be null, please init first");
      currentValueStr = (String)this.stringRedisTemplate.execute(this.distributionIdGeneratorLua, 
          
          (List)ImmutableList.of(key), new Object[] { "getDistributionId", 
            
            String.valueOf(DISTRIBUTION_ID_INCR_STEP), 
            String.valueOf(currentMilliSeconds), 
            String.valueOf(distributionId.getMaxValueAvailable()) });
    } 
    if (StringUtils.isEmpty(currentValueStr))
      return null; 
    String[] currentValueArray = StringUtils.commaDelimitedListToStringArray(currentValueStr);
    if (currentValueArray.length != DISTRIBUTION_ID_RESULT_SUCC_COUNT.intValue())
      return null; 
    Long currentValue = Long.valueOf(currentValueArray[0]);
    Long maxValueAvailable = Long.valueOf(currentValueArray[1]);
    Long maxValueAvailableRefresh = Long.valueOf(currentValueArray[2]);
    if (!maxValueAvailable.equals(maxValueAvailableRefresh)) {
      DistributionId sample = new DistributionId();
      sample.setBizType(bizType);
      DistributionId distributionId = (DistributionId)this.distributionIdRepository.selectOne(sample);
      Assert.notNull(distributionId, "Distribution cannot be null, please init first");
      distributionId.setMaxValueAvailable(maxValueAvailableRefresh);
      this.distributionIdRepository.updateOptional(distributionId, new String[] { "maxValueAvailable" });
    } 
    return currentValue;
  }
}
